package net.maku.events.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.xiaoymin.knife4j.core.util.CollectionUtils;
import lombok.RequiredArgsConstructor;
import net.maku.events.convert.UserJoinActivityConvert;
import net.maku.events.dao.*;
import net.maku.events.entity.*;
import net.maku.events.enums.ActivityStatusEnum;
import net.maku.events.enums.WhetherAddEnum;
import net.maku.events.query.ActivityRankQuery;
import net.maku.events.query.UserPointsRecordsQuery;
import net.maku.events.service.UserPointsRecordsService;
import net.maku.events.vo.RankMemberUserVO;
import net.maku.events.vo.RankOrgVO;
import net.maku.events.vo.UserPointsRecordsVO;
import net.maku.framework.common.utils.DateUtils;
import net.maku.framework.common.utils.PageResult;
import net.maku.framework.mybatis.service.impl.BaseServiceImpl;
import net.maku.framework.security.user.SecurityUser;
import net.maku.member.dao.MemberUserDao;
import net.maku.member.entity.MemberUserEntity;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: qr
 * @Date: 2025/3/25 22:52
 * @Version 1.0
 */
@Service
@RequiredArgsConstructor
public class UserPointsRecordsServiceImpl extends BaseServiceImpl<UserPointsRecordsDao, UserPointsRecordsEntity> implements UserPointsRecordsService {

    private final UserPointsRecordsDao userPointsRecordsDao;

    private final MemberUserDao memberUserDao;

    private final UserEarningsCardDao userEarningsCardDao;

    private final ActivityRankSnapshotDao activityRankSnapshotDao;

    private final ActivityRankSnapshotTodayDao activityRankSnapshotTodayDao;

    private final ActivityRankOrgSnapshotDao activityRankOrgSnapshotDao;

    private final ActivityBriskWalkDao activityBriskWalkDao;

    @Override
    public PageResult<UserPointsRecordsVO> page(UserPointsRecordsQuery query) {
        IPage<UserPointsRecordsEntity> page = baseMapper.selectPage(getPage(query), getWrapper(query));
        return new PageResult<>(BeanUtil.copyToList(page.getRecords(), UserPointsRecordsVO.class), page.getTotal());
    }

    @Override
    public Map<String, Double> userPoint() {
        Map<String, Double> pointMap = new HashMap<>();
        MemberUserEntity memberUserEntity = memberUserDao.selectById(SecurityUser.getUserId());
        pointMap.put("reducePoint", 0.0);
        pointMap.put("addPoint", 0.0);
        pointMap.put("nowPoint", memberUserEntity.getPoints());
        List<UserPointsRecordsEntity> entityList = baseMapper.selectList(new LambdaQueryWrapper<UserPointsRecordsEntity>().eq(UserPointsRecordsEntity::getUserId, SecurityUser.getUserId()));
        if (CollectionUtils.isNotEmpty(entityList)) {
            Map<Integer, List<UserPointsRecordsEntity>> entityMap = entityList.stream().collect(Collectors.groupingBy(UserPointsRecordsEntity::getWhetherAdd));
            if (CollectionUtils.isNotEmpty(entityMap.get(WhetherAddEnum.ADD.getType()))) {
                pointMap.put("addPoint", entityMap.get(WhetherAddEnum.ADD.getType()).stream().mapToDouble(UserPointsRecordsEntity::getPoints).sum());
            }
            if (CollectionUtils.isNotEmpty(entityMap.get(WhetherAddEnum.DECREASE.getType()))) {
                pointMap.put("reducePoint", entityMap.get(WhetherAddEnum.DECREASE.getType()).stream().mapToDouble(UserPointsRecordsEntity::getPoints).sum());
            }
        }
        return pointMap;
    }

    @Override
    public RankMemberUserVO userSelfRank(ActivityRankQuery query) {
//        RankMemberUserVO rankMemberUserVO = userPointsRecordsDao.userSelfRank(query, SecurityUser.getUserId());
        if (query.getTodayFlag()) {
            RankMemberUserVO rankMemberUserVO = BeanUtil.copyProperties(activityRankSnapshotTodayDao.selectOne(new LambdaQueryWrapper<ActivityRankSnapshotTodayEntity>()
                    .eq(ActivityRankSnapshotTodayEntity::getUserId, SecurityUser.getUserId())
                    .eq(ActivityRankSnapshotTodayEntity::getActivityId, query.getActivityId())
                    .eq(ActivityRankSnapshotTodayEntity::getBusinessType, query.getActivityType())), RankMemberUserVO.class);
            if (ObjectUtils.isNotEmpty(rankMemberUserVO)) {
                rankMemberUserVO.setRanks(rankMemberUserVO.getRanks() + 1);
            }
            return rankMemberUserVO;
        } else {
            RankMemberUserVO rankMemberUserVO = BeanUtil.copyProperties(activityRankSnapshotDao.selectOne(new LambdaQueryWrapper<ActivityRankSnapshotEntity>()
                    .eq(ActivityRankSnapshotEntity::getUserId, SecurityUser.getUserId())
                    .eq(ActivityRankSnapshotEntity::getActivityId, query.getActivityId())
                    .eq(ActivityRankSnapshotEntity::getBusinessType, query.getActivityType())), RankMemberUserVO.class);
            if (ObjectUtils.isNotEmpty(rankMemberUserVO)) {
                rankMemberUserVO.setRanks(rankMemberUserVO.getRanks() + 1);
            }
            return rankMemberUserVO;
        }
    }

    @Override
    public List<RankMemberUserVO> getRank(Long businessId, Integer businessType, boolean todayFlag) {
        List<RankMemberUserVO> rankMemberUserVOList = userPointsRecordsDao.getRank(businessId, businessType, todayFlag);
        if (CollectionUtils.isNotEmpty(rankMemberUserVOList)) {
            List<UserEarningsCardEntity> earningsCardEntityList = userEarningsCardDao.selectList(new LambdaQueryWrapper<UserEarningsCardEntity>().eq(UserEarningsCardEntity::getBriskWalkId, businessId)
                    .in(UserEarningsCardEntity::getUserId, rankMemberUserVOList.stream().map(RankMemberUserVO::getId).collect(Collectors.toList())));
            if (CollectionUtils.isNotEmpty(earningsCardEntityList)) {
                Map<Long, List<UserEarningsCardEntity>> earningsCardMap = earningsCardEntityList.stream().collect(Collectors.groupingBy(UserEarningsCardEntity::getUserId));
                rankMemberUserVOList.forEach(item -> {
                    item.setPoints(item.getPoints() > 20 ? 20 : item.getPoints());
                    // 获取当前用户的卡列表（可能为null或空）
                    List<UserEarningsCardEntity> cardList = earningsCardMap.get(item.getId());
                    long cardCount = (cardList != null) ? cardList.size() : 0L;
                    item.setCardNumber(cardCount);
                    if (CollectionUtils.isNotEmpty(cardList)) {
                        LocalDateTime latestTime = cardList.stream()
                                .map(UserEarningsCardEntity::getCreateTime)
                                .max(LocalDateTime::compareTo)
                                .orElse(null);
                        item.setAcquireCardTime(latestTime);
                    }
                });
            }
        }
        if (CollectionUtils.isEmpty(rankMemberUserVOList)) {
            return rankMemberUserVOList;
        }
        Comparator<RankMemberUserVO> comparator = Comparator
                .comparingDouble(RankMemberUserVO::getPoints).reversed() // 积分降序（最高优先）
                .thenComparing(Comparator.comparingLong(RankMemberUserVO::getCardNumber).reversed())  // 集卡数降序
                .thenComparing(RankMemberUserVO::getAcquireCardTime, Comparator.nullsLast(Comparator.naturalOrder()))  // 时间戳升序
                .thenComparing(RankMemberUserVO::getTime, Comparator.nullsLast(Comparator.naturalOrder()));  // 最后时间升序
        rankMemberUserVOList.sort(comparator);
        for (int i = 0; i < rankMemberUserVOList.size(); i++) {
            rankMemberUserVOList.get(i).setRanks(i + 1);
        }
        return rankMemberUserVOList;
    }

    @Override
    public PageResult<RankMemberUserVO> getRankPage(ActivityRankQuery query) {
//        IPage<RankMemberUserVO> page = userPointsRecordsDao.getRankPage(new Page<UserJoinActivityEntity>(query.getPage(), query.getLimit()), query);
//        List<RankMemberUserVO> rankMemberUserVOList = page.getRecords();
//        if (CollectionUtils.isNotEmpty(page.getRecords())) {
//            int index = (query.getPage() - 1) * query.getLimit();
//            for (int i = 0; i < rankMemberUserVOList.size();
//                 i++) {
//                rankMemberUserVOList.get(i).setRanks(index + i + 1);
//            }
//        }
        if (query.getTodayFlag()) {
            IPage<ActivityRankSnapshotTodayEntity> page = activityRankSnapshotTodayDao.selectPage(new Page<ActivityRankSnapshotTodayEntity>(query.getPage(), query.getLimit()),
                    new LambdaQueryWrapper<ActivityRankSnapshotTodayEntity>().eq(ActivityRankSnapshotTodayEntity::getActivityId, query.getActivityId())
                            .eq(ActivityRankSnapshotTodayEntity::getBusinessType, query.getActivityType()).orderByDesc(ActivityRankSnapshotTodayEntity::getPoints)
                            .orderByDesc(ActivityRankSnapshotTodayEntity::getStepNumber)
                            .orderByDesc(ActivityRankSnapshotTodayEntity::getCardNumber)
                            .orderByAsc(ActivityRankSnapshotTodayEntity::getAcquireCardTime)
            );
            List<RankMemberUserVO> rankMemberUserVOList = BeanUtil.copyToList(page.getRecords(), RankMemberUserVO.class);
            if (CollectionUtils.isNotEmpty(page.getRecords())) {
                int index = (query.getPage() - 1) * query.getLimit();
                for (int i = 0; i < rankMemberUserVOList.size();
                     i++) {
                    rankMemberUserVOList.get(i).setRanks(index + i + 1);
                }
            }
            return new PageResult<>(rankMemberUserVOList, page.getTotal());
        } else {
            IPage<ActivityRankSnapshotEntity> page = activityRankSnapshotDao.selectPage(new Page<ActivityRankSnapshotEntity>(query.getPage(), query.getLimit()),
                    new LambdaQueryWrapper<ActivityRankSnapshotEntity>().eq(ActivityRankSnapshotEntity::getActivityId, query.getActivityId())
                            .eq(ActivityRankSnapshotEntity::getBusinessType, query.getActivityType()).orderByDesc(ActivityRankSnapshotEntity::getPoints)
                            .orderByDesc(ActivityRankSnapshotEntity::getStepNumber)
                            .orderByDesc(ActivityRankSnapshotEntity::getCardNumber)
                            .orderByAsc(ActivityRankSnapshotEntity::getAcquireCardTime));
            List<RankMemberUserVO> rankMemberUserVOList = BeanUtil.copyToList(page.getRecords(), RankMemberUserVO.class);
            if (CollectionUtils.isNotEmpty(page.getRecords())) {
                int index = (query.getPage() - 1) * query.getLimit();
                for (int i = 0; i < rankMemberUserVOList.size();
                     i++) {
                    rankMemberUserVOList.get(i).setRanks(index + i + 1);
                }
            }
            return new PageResult<>(rankMemberUserVOList, page.getTotal());
        }

    }

    @Override
    public List<RankOrgVO> getRankOrg(Long businessId, Integer businessType) {
//        List<RankOrgVO> result = userPointsRecordsDao.getRankOrg(businessId, businessType);
//        if (CollectionUtils.isEmpty(result)) {
//            return result;
//        }
//        Comparator<RankOrgVO> comparator = Comparator
//                .comparingDouble(RankOrgVO::getPoints).reversed()
//                .thenComparing(Comparator.comparingLong(RankOrgVO::getCardNumber).reversed());
//        result.sort(comparator);
//        for (int i = 0; i < result.size(); i++) {
//            result.get(i).setRanks(i + 1);
//        }
        List<RankOrgVO> result = BeanUtil.copyToList(activityRankOrgSnapshotDao.selectList(new LambdaQueryWrapper<ActivityRankOrgSnapshotEntity>().eq(ActivityRankOrgSnapshotEntity::getActivityId, businessId)
                .eq(ActivityRankOrgSnapshotEntity::getBusinessType, businessType)), RankOrgVO.class);
        Comparator<RankOrgVO> comparator = Comparator
                .comparingDouble(RankOrgVO::getPoints).reversed()
                .thenComparing(Comparator.comparingLong(RankOrgVO::getCardNumber).reversed());
        result.sort(comparator);
        return result;
    }

    private LambdaQueryWrapper<UserPointsRecordsEntity> getWrapper(UserPointsRecordsQuery query) {
        LambdaQueryWrapper<UserPointsRecordsEntity> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(UserPointsRecordsEntity::getUserId, SecurityUser.getUserId()).orderByDesc(UserPointsRecordsEntity::getCreateTime);
        return wrapper;
    }

    @Override
    public void insertUserPointsRecords(Long businessId, Integer businessType, Double points, Integer whetherAdd) {
        UserPointsRecordsEntity entity = new UserPointsRecordsEntity();
        entity.setBusinessId(businessId);
        entity.setBusinessType(businessType);
        entity.setPoints(points);
        entity.setWhetherAdd(whetherAdd);
        entity.setUserId(SecurityUser.getUserId());
        this.save(entity);
        MemberUserEntity memberUserEntity = memberUserDao.selectById(SecurityUser.getUserId());
        if (whetherAdd.equals(WhetherAddEnum.ADD.getType())) {
            memberUserEntity.setPoints(memberUserEntity.getPoints() + points);
        } else {
            memberUserEntity.setPoints(memberUserEntity.getPoints() - points);
        }
        memberUserDao.updateById(memberUserEntity);
    }


    @Scheduled(cron = "0 0/5 * * * ? ")
    @Transactional(rollbackFor = Exception.class)
    public void generateRankSnapshot() {
        List<ActivityBriskWalkEntity> entityList = activityBriskWalkDao.selectList(new LambdaQueryWrapper<ActivityBriskWalkEntity>().eq(ActivityBriskWalkEntity::getActivityStatus, ActivityStatusEnum.BEGIN.getStatus())
                .apply("date_format(activity_end_time,'%Y-%m-%d %H:%i:%s') >= date_format ({0},'%Y-%m-%d %H:%i:%s')", DateUtils.format(new Date(), DateUtils.DATE_TIME_PATTERN)));
        if (CollectionUtils.isNotEmpty(entityList)) {
            entityList.forEach(entity -> {
                activityRankSnapshotDao.delete(new LambdaQueryWrapper<ActivityRankSnapshotEntity>().gt(ActivityRankSnapshotEntity::getSnapshotId, 1).eq(ActivityRankSnapshotEntity::getActivityId, entity.getId()));
                activityRankSnapshotTodayDao.delete(new LambdaQueryWrapper<ActivityRankSnapshotTodayEntity>().gt(ActivityRankSnapshotTodayEntity::getSnapshotId, 1).eq(ActivityRankSnapshotTodayEntity::getActivityId, entity.getId()));
                activityRankOrgSnapshotDao.delete(new LambdaQueryWrapper<ActivityRankOrgSnapshotEntity>().gt(ActivityRankOrgSnapshotEntity::getSnapshotId, 1).eq(ActivityRankOrgSnapshotEntity::getActivityId, entity.getId()));
                userPointsRecordsDao.generateRankSnapshot(entity.getId(), 7);
                userPointsRecordsDao.generateRankSnapshotToday(entity.getId(), 7, true);
                userPointsRecordsDao.generateOrgRankSnapshot(entity.getId(), 7);
            });
        }
    }
}
